/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <unistd.h>
#include "pag_napi_comPosition.h"
#include "hilog/log.h"
#include "pag/pag.h"
#include <bits/alltypes.h>
#include "pag_napi_pagFile.h"
#include <iostream>
#include <fstream>
#include <filesystem>
#include "PagSurface.h"
#include <unistd.h>
#include <iostream>
#include "napi/PagCompositionProxy.h"

namespace NativeXComponentSample {
const int32_t STR_DEFAULT_SIZE = 2048;
const int32_t INDEX_0 = 0;
const int32_t INDEX_1 = 1;
const int32_t INDEX_2 = 2;
const int32_t INDEX_3 = 3;
const int32_t PARAM_COUNT_1 = 1;
const int32_t PARAM_COUNT_2 = 2;
const int32_t PARAM_COUNT_3 = 3;
const int32_t PARAM_COUNT_4 = 4;

const unsigned int LOG_PRINT_DOMAIN = 0XFF00;
napi_ref PAGComposition::sJSPlayerConstructor_ = nullptr;

std::unordered_map<std::string, PAGComposition *> PAGComposition::pagCompositionNapiMap_;

PAGComposition::PAGComposition(napi_env pEnv, std::string &id)
{
    mEnv = pEnv;
    pagCompositionProxy_ = new PagCompositionProxy(id);
};

PAGComposition::PAGComposition(napi_env pEnv, napi_ref pRef)
{
    mEnv = pEnv;
    mRef = pRef;
}

PAGComposition::~PAGComposition()
{
    if (mRef != nullptr) {
        napi_delete_reference(mEnv, mRef);
    }
    for (auto iter = pagCompositionNapiMap_.begin(); iter != pagCompositionNapiMap_.end(); ++iter) {
        if (iter->second != nullptr) {
            delete iter->second;
            iter->second = nullptr;
        }
    }
    pagCompositionNapiMap_.clear();
}

void PAGComposition::Destructor(napi_env env, void *nativeObject, void *finalize)
{
    PAGComposition *pagPlayer = reinterpret_cast<PAGComposition *>(nativeObject);
    pagPlayer->PAGComposition::~PAGComposition();
}

PAGComposition *PAGComposition::getInstance(napi_env pEnv, std::string &id)
{
    if (pagCompositionNapiMap_.find(id) == pagCompositionNapiMap_.end()) {
        PAGComposition *instance = new PAGComposition(pEnv, id);
        pagCompositionNapiMap_[id] = instance;
        return instance;
    } else {
        return pagCompositionNapiMap_[id];
    }
}

std::string GetCurrentXCompentId(napi_env env, napi_callback_info info)
{
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PAGComposition", "GetCurrentXCompentId");
    size_t argc = PARAM_COUNT_1;
    napi_value args[INDEX_1] = { nullptr };
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    char diStr[1024] = {0};
    size_t charLen = 0;
    napi_get_value_string_utf8(env, args[0], diStr, STR_DEFAULT_SIZE, &charLen);
    std::string idCompent = diStr;
    return idCompent;
}

PAGComposition *PAGComposition::GetNapiComposition(napi_env env, napi_callback_info info)
{
    napi_value thisVar = nullptr;
    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
    PAGComposition *pagComposition = nullptr;
    napi_unwrap(env, thisVar, reinterpret_cast<void **>(&pagComposition));
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "INIT",
        "PAGPlayer::PagInit pagPlayer = %{public}p", pagComposition);
    return pagComposition;
}

napi_value PAGComposition::PAGCompositionInit(napi_env env, napi_callback_info info)
{
    GetNapiComposition(env, info)->pagCompositionProxy_->PAGCompositionInit(env, info);
    return nullptr;
}

napi_value PAGComposition::AddLayer(napi_env env, napi_callback_info info)
{
    GetNapiComposition(env, info)->pagCompositionProxy_->AddLayer(env, info);
    return nullptr;
}

napi_value PAGComposition::GetLayerAt(napi_env env, napi_callback_info info)
{
    GetNapiComposition(env, info)->pagCompositionProxy_->GetLayerAt(env, info);
    return nullptr;
}

napi_value PAGComposition::RemoveLayer(napi_env env, napi_callback_info info)
{
    GetNapiComposition(env, info)->pagCompositionProxy_->RemoveLayer(env, info);
    return nullptr;
}

napi_value PAGComposition::RemoveAllLayers(napi_env env, napi_callback_info info)
{
    GetNapiComposition(env, info)->pagCompositionProxy_->RemoveAllLayers(env, info);
    return nullptr;
}

napi_value PAGComposition::NumChildren(napi_env env, napi_callback_info info)
{
    return GetNapiComposition(env, info)->pagCompositionProxy_->NumChildren(env, info);
}

napi_value PAGComposition::JsPlayerConstructor(napi_env env, napi_callback_info info)
{
    napi_value undefineVar = nullptr;
    napi_value thisVar = nullptr;
    napi_get_undefined(env, &undefineVar);

    if (napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr) == napi_ok && thisVar != nullptr) {
        // 创建PAGComposition 实例
        std::string xCompentId = GetCurrentXCompentId(env, info);
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "INIT", "PAGComposition::JsPlayerConstructor = %{public}s",
                     xCompentId.c_str());
        PAGComposition *reference = PAGComposition::getInstance(env, xCompentId);
        // 绑定实例类创建PAGComposition到导出的对象result
        if (napi_wrap(env, thisVar, reinterpret_cast<void *>(reference), PAGComposition::Destructor, nullptr,
            &(reference->mRef)) == napi_ok) {
            return thisVar;
        }
        return thisVar;
    }

    return undefineVar;
}

napi_value PAGComposition::AddLayerAt(napi_env env, napi_callback_info info)
{
    GetNapiComposition(env, info)->pagCompositionProxy_->AddLayerAt(env, info);
    return nullptr;
}

napi_value PAGComposition::RemoveLayerAt(napi_env env, napi_callback_info info)
{
    GetNapiComposition(env, info)->pagCompositionProxy_->RemoveLayerAt(env, info);
    return nullptr;
}
} // namespace NativeXComponentSample